From 5c088f69320e1f2636c8c577a3c599bda5fd8d3c Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sun, 9 Jul 2017 11:48:54 +0300 Subject: [PATCH] Specify conventions for benches, examples and tests only once --- src/cargo/util/toml/targets.rs | 57 ++++++++++++++++++++++++---------- tests/build.rs | 26 ++++++++++++++++ 2 files changed, 66 insertions(+), 17 deletions(-) diff --git a/src/cargo/util/toml/targets.rs b/src/cargo/util/toml/targets.rs index fce7d1d4a..7789ad522 100644 --- a/src/cargo/util/toml/targets.rs +++ b/src/cargo/util/toml/targets.rs @@ -139,12 +139,12 @@ impl Layout { } fn infer_from_directory(directory: &Path) -> Vec<(String, PathBuf)> { - let directory = match fs::read_dir(directory) { + let entries = match fs::read_dir(directory) { Err(_) => return Vec::new(), Ok(dir) => dir }; - directory.filter_map(|entry| entry.map(|d| d.path()).ok()) + entries.filter_map(|entry| entry.map(|d| d.path()).ok()) .filter(|f| f.extension().and_then(|s| s.to_str()) == Some("rs")) .filter_map(|f| { if f.file_name().and_then(|n| n.to_str()).map(|n| n.starts_with('.')) != Some(false) { @@ -286,16 +286,16 @@ fn clean_bins(toml_bins: Option<&Vec>, fn clean_examples(toml_examples: Option<&Vec>, package_root: &Path) -> CargoResult> { + let inferred = inferred_examples(package_root); let examples = match toml_examples { Some(examples) => examples.clone(), - None => inferred_examples(package_root).into_iter().map(|(name, path)| { + None => inferred.iter().map(|&(ref name, ref path)| { TomlTarget { - name: Some(name), - path: Some(PathValue(path)), + name: Some(name.clone()), + path: Some(PathValue(path.clone())), ..TomlTarget::new() } }).collect() - }; for target in examples.iter() { @@ -306,9 +306,7 @@ fn clean_examples(toml_examples: Option<&Vec>, let mut result = Vec::new(); for ex in examples.iter() { - let path = ex.path.clone().unwrap_or_else(|| { - PathValue(Path::new("examples").join(&format!("{}.rs", ex.name()))) - }); + let path = target_path(ex, &inferred, "example", package_root)?; let crate_types = match ex.crate_types() { Some(kinds) => kinds.iter().map(|s| LibKind::from_str(s)).collect(), @@ -318,7 +316,7 @@ fn clean_examples(toml_examples: Option<&Vec>, let mut target = Target::example_target( &ex.name(), crate_types, - package_root.join(&path.0), + path, ex.required_features.clone() ); configure(ex, &mut target); @@ -330,12 +328,13 @@ fn clean_examples(toml_examples: Option<&Vec>, fn clean_tests(toml_tests: Option<&Vec>, package_root: &Path) -> CargoResult> { + let inferred = inferred_tests(package_root); let tests = match toml_tests { Some(tests) => tests.clone(), - None => inferred_tests(package_root).into_iter().map(|(name, path)| { + None => inferred.iter().map(|&(ref name, ref path)| { TomlTarget { - name: Some(name), - path: Some(PathValue(path)), + name: Some(name.clone()), + path: Some(PathValue(path.clone())), ..TomlTarget::new() } }).collect() @@ -349,11 +348,9 @@ fn clean_tests(toml_tests: Option<&Vec>, let mut result = Vec::new(); for test in tests.iter() { - let path = test.path.clone().unwrap_or_else(|| { - PathValue(Path::new("tests").join(&format!("{}.rs", test.name()))) - }); + let path = target_path(test, &inferred, "test", package_root)?; - let mut target = Target::test_target(&test.name(), package_root.join(&path.0), + let mut target = Target::test_target(&test.name(), path, test.required_features.clone()); configure(test, &mut target); result.push(target); @@ -504,6 +501,32 @@ fn inferred_bin_targets(name: &str, layout: &Layout, project_root: &Path) -> Vec }).collect() } +fn target_path(target: &TomlTarget, + inferred: &[(String, PathBuf)], + target_kind: &str, + package_root: &Path) -> CargoResult { + if let Some(ref path) = target.path { + // Should we verify that this path exists here? + return Ok(package_root.join(&path.0)); + } + let name = target.name(); + + let mut matching = inferred.iter() + .filter(|&&(ref n, _)| n == &name) + .map(|&(_, ref p)| p.clone()); + + let first = matching.next(); + let second = matching.next(); + match (first, second) { + (Some(path), None) => Ok(path), + (None, None) | (Some(_), Some(_)) => { + bail!("can't find `{name}` {target_kind}, specify {target_kind}.path", + name = name, target_kind = target_kind) + } + (None, Some(_)) => unreachable!() + } +} + fn validate_has_name(target: &TomlTarget, target_name: &str, target_kind: &str) -> CargoResult<()> { match target.name { Some(ref name) => if name.trim().is_empty() { diff --git a/tests/build.rs b/tests/build.rs index 9a7c51e63..7cbcf5e68 100644 --- a/tests/build.rs +++ b/tests/build.rs @@ -1350,6 +1350,32 @@ fn explicit_examples() { execs().with_status(0).with_stdout("Goodbye, World!\n")); } +#[test] +fn non_existing_example() { + let mut p = project("world"); + p = p.file("Cargo.toml", r#" + [package] + name = "world" + version = "1.0.0" + authors = [] + + [lib] + name = "world" + path = "src/lib.rs" + + [[example]] + name = "hello" + "#) + .file("src/lib.rs", "") + .file("examples/ehlo.rs", ""); + + assert_that(p.cargo_process("test").arg("-v"), execs().with_status(101).with_stderr("\ +[ERROR] failed to parse manifest at `[..]` + +Caused by: + can't find `hello` example, specify example.path")); +} + #[test] fn implicit_examples() { let mut p = project("world"); -- 2.30.2